package com.service.impl;


import com.bean.JwtOperation;
import com.constant.AppConstant;
import com.dto.JsonResult;
import com.dto.User;
import com.dto.UserAndRoleDecn;
import com.entity.Role;
import com.entity.UserAndRole;
import com.entity.UserInfo;
import com.repository.UserAndRoleRepository;
import com.repository.UserRepository;
import com.service.UserService;
import com.vo.UserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Service
public class UserServiceImpl implements UserService {

    //用于获取认证管理器
    @Autowired
    private AuthenticationConfiguration authenticationConfiguration;

    @Autowired
    private JwtOperation jwtOperation;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    @Qualifier("jdbcUseService")
    private UserDetailsService userDetailsService;

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserAndRoleRepository userAndRoleRepository;


    /**
     * 通过用户名判断用户是否存在
     *
     * @param username 用户名
     * @return
     */

    public boolean isExist(String username) {
        UserInfo user = userRepository.findByUsername(username);
        return user != null;
    }

    /**
     * 通过用户名查询用户
     *
     * @param username 用户名
     * @return
     */
    @Override
    public UserInfo findByUsername(String username) {
        return userRepository.findByUsername(username);
    }


    /**
     * 通过用户名密码查询用户
     *
     * @param username 用户名
     * @param password 密码
     * @return
     */
    @Override
    public boolean get(String username, String password) {
        return userRepository.getByUsernameAndPassword(username, password) != null;

    }

    @Override
    public List<UserInfo> findAll() {

        return userRepository.findAll();
    }

    @Override
    public JsonResult login(String name, String pwd) throws Exception {


        //获取认证管理器
        AuthenticationManager authenticationManager = authenticationConfiguration.getAuthenticationManager();
        //用户验证:这里只需要构建一个UsernamePasswordAuthenticationToken，给定用户名和密码，验证过程由SpringSecurity完成
        //这里认证出错会出现BadCredentialsException异常，捕获处理即可
        //这里的校验逻辑大致为：
        // encoder.matches("明文密码","数据库中存储的密码")，因此数据库存储的应该是加密密码，否则无法校验
        Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(name, pwd));
        //存储认证信息
        SecurityContextHolder.getContext().setAuthentication(authentication);
        //获取认证通过的具体用户信息
        UserDetails userDetails = userDetailsService.loadUserByUsername(name);
        UserInfo userInfo = userRepository.findByUsername(name);
        //构建用于生成JWT的用户对象
        User user = new User();
        user.setId(userInfo.getId());
        user.setAvatar(userInfo.getAvatar());
        user.setIntroduction(userInfo.getIntroduction());
        user.setName(userDetails.getUsername());
        user.setPassword(userDetails.getPassword());
        user.setRoles(userDetails.getAuthorities().stream().map(
                e -> ((GrantedAuthority) e).getAuthority()).collect(Collectors.toList()));
//        System.out.println(user);
        //创建JWT
        String token = jwtOperation.creatJwt(user);
        if (stringRedisTemplate.hasKey(AppConstant.DEFAULT_NAME_PREFIX)!=null) {
            stringRedisTemplate.delete(AppConstant.DEFAULT_NAME_PREFIX);
        }
        stringRedisTemplate.opsForValue().set(AppConstant.DEFAULT_NAME_PREFIX, token);
        //设置过期时间
        stringRedisTemplate.expire(AppConstant.DEFAULT_NAME_PREFIX, 60*30, TimeUnit.SECONDS);


        user.setPassword(null);
        //登录成功返回用户基本信息以及Token
        Map<String, Object> data = new LinkedHashMap<String, Object>() {{
            put("token", token);
            put("userInfo", user);
        }};
        return JsonResult.buildSuccess(201, data);
    }

    @Override
    public List<UserAndRoleDecn> list() {
        List<UserInfo> all = userRepository.findAll();
        List<UserAndRoleDecn> list = new ArrayList<>();
        for (UserInfo userInfo : all) {
            UserAndRoleDecn userAndRoleDecn = new UserAndRoleDecn();
            userAndRoleDecn.setId(userInfo.getId());
            userAndRoleDecn.setNickname(userInfo.getNickname());
            userAndRoleDecn.setUsername(userInfo.getUsername());
            userAndRoleDecn.setEmail(userInfo.getEmail());
            userAndRoleDecn.setPhone(userInfo.getPhone());
            userAndRoleDecn.setEnabled(userInfo.isEnabled());
            List<Role> roles = userInfo.getRoles();
            for (Role role : roles) {
                userAndRoleDecn.setName_zh(role.getNameZh());

                list.add(userAndRoleDecn);
            }
        }
        return list;
    }


    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateUserStatus(UserInfo userInfo) {
        UserInfo username = userRepository.findByUsername(userInfo.getUsername());
        username.setEnabled(userInfo.isEnabled());
        userRepository.save(username);
    }

    /**
     * 重置用户密码
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public UserInfo resetPassword(UserInfo userInfo) {
        String password = AppConstant.DEFAULT_PASSWORD;
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        String newPassword = passwordEncoder.encode(password);
        UserInfo byUsername = userRepository.findByUsername(userInfo.getUsername());
        byUsername.setPassword(newPassword);
        return userRepository.save(byUsername);
    }

    /**
     * 修改/编辑用户信息
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void editUser(UserVo userVo) {
        if (userRepository.findById(userVo.getUserInfo().getId()).isPresent()) {
            UserInfo userInfo = userRepository.findById(userVo.getUserInfo().getId()).get();
            userInfo.setEmail(userVo.getUserInfo().getEmail());
            userInfo.setPhone(userVo.getUserInfo().getPhone());
            userInfo.setNickname(userVo.getUserInfo().getNickname());
            userRepository.save(userInfo);
        }
        UserAndRole role = userAndRoleRepository.findByUid(userVo.getUserInfo().getId());
        role.setRid(userVo.getRid());
        userAndRoleRepository.save(role);
    }


    /**
     * 新增用户
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void addUser(UserVo userVo) {
        //TODO:先用户添加然后中间表创建关联。新增用户可封装
        UserInfo userInfo = new UserInfo();
        userInfo.setId(userVo.getUserInfo().getId());
        userInfo.setUsername(userVo.getUserInfo().getUsername());
        userInfo.setNickname(userVo.getUserInfo().getNickname());
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        userInfo.setPassword(passwordEncoder.encode(userVo.getUserInfo().getPassword()));
        userInfo.setAdmin(AppConstant.DEFAULT_IS_ADMIN);
        userInfo.setEnabled(AppConstant.DEFAULT_IS_ENABLE);
        userInfo.setStatus(AppConstant.DEFAULT_STATUS);
        userInfo.setCreatedTime(new Date());
        userRepository.save(userInfo);

        UserAndRole userAndRole = new UserAndRole();
        userAndRole.setRid(userVo.getRid());
        userAndRole.setUid(userRepository.findByUsername(userVo.getUserInfo().getUsername()).getId());
        userAndRoleRepository.save(userAndRole);

    }

    /**
     * 按id查询
     *
     * @param id
     * @return
     */
    @Override
    public boolean findById(Integer id) {
        Optional<UserInfo> optional = userRepository.findById(id);
        return optional.isPresent();
    }

    /**
     * 按id查询所有符合的数据
     *
     * @param ids
     * @return
     */
    @Override
    public boolean findByIds(List<Integer> ids) {
        List<UserInfo> all = userRepository.findAllById(ids);
        return all.size() == ids.size();
    }

    /**
     * 批量删除
     *
     * @param ids 批量删除需要的id
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteByIds(List<Integer> ids) {
        List<Integer> list = ids;
        for (Integer integer : list) {
            userRepository.deleteById(integer);
            userAndRoleRepository.delUserInRole(integer);
        }
    }

    /**
     * 单删除
     *
     * @param id
     */
    @Override
    @Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteById(Integer id) {
        userRepository.deleteById(id);
        userAndRoleRepository.delUserInRole(id);
    }
}
